using System;
using System.Collections.Generic;
using System.Data;
using System.Configuration;
using System.Collections;
using System.IO;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Gui.AspNet2;
using Syrinx.Gui.AspNet.Ajax;

public partial class AjaxRequestHandler : System.Web.UI.Page, INitobiPage
{
	protected Swaf.Gui.AspNet2.ServerControlLocalizer m_localizer;
	protected Control m_pageForm = null;
	protected BizProcCoordinator m_bpc = null;
	protected XmlDocument m_browserStateDoc = null;
	protected string m_pageRequestId = "";
	protected ActiveWidget m_eventWidget = null;
	protected string m_newView = null;

	protected override void OnPreInit(EventArgs e)
	{
		base.OnPreInit(e);
		//Setting up the ajax response theme allows controls that were created dynamically to be properly
		//setup with the current theme.
		if (CurrentUser != null && CurrentUser.containsField("settings.themeName"))
		{
			string themeName = CurrentUser.get("settings.themeName") as string;
			if (!Cmn.IsEmpty(themeName))
				Page.Theme = themeName;
		}

	}
	public IBizObj CurrentUser { get { return App.securityMgr.currentPrincipal.additionalInfo as IBizObj; } }

	public IWidget findWidget(string widgetId)
	{
		Control ctl = findControl(this, widgetId);
		return ctl as IWidget;
	}

	protected Control findControl(Control parent, string id)
	{
		Control ctl = null;

		foreach (Control childCtl in parent.Controls)
			if (childCtl.ID != null && childCtl.ID.CompareTo(id) == 0)
			{
				ctl = childCtl;
				break;
			}

		if (ctl == null)
			foreach (Control childCtl in parent.Controls)
				if ((ctl = findControl(childCtl, id)) != null)
					break;
		return ctl;
	}

	protected override void OnInitComplete(EventArgs e)
	{
		base.OnInitComplete(e);
		m_pageForm = FindControl("form1");

		Response.ContentType = "text/xml";
		Response.AddHeader("Pragma", "no-cache");
		Response.AddHeader("Expires", "Tue, 01 Jan 1980 1:00:00 GMT");
		m_pageRequestId = Request["pi"];
		string requestType = Request["RequestType"];

		StreamReader rdr = new StreamReader(Request.InputStream);
		string xml = rdr.ReadToEnd();
		rdr.Close();

		try
		{
			string ajaxOutLoc = (string)App.appData.get("AjaxDebugOutput");
			if (!Cmn.IsEmpty(ajaxOutLoc))
				File.WriteAllText(Cmn.pathCombine(ajaxOutLoc, "IN-" + DateTime.Now.ToString("yyMMddHHmmssF") + ".xml"), xml);
		}
		catch (Exception) { }

		m_browserStateDoc = new XmlDocument();
		m_browserStateDoc.LoadXml(xml);

		string actionWidgetId = m_browserStateDoc.DocumentElement.GetAttribute("id");
		m_eventWidget = BPC.getActiveWidget(actionWidgetId);
		//m_eventBizProc = BPC.getActiveBizProc(m_browserStateDoc.DocumentElement.GetAttribute("bizProcId"));
	}

	protected override void OnLoadComplete(EventArgs e)
	{
		base.OnLoadComplete(e);

		if (m_eventWidget != null && m_eventWidget.Widget is IAjaxClientControl)
		{
			IAjaxClientControl ctl = m_eventWidget.Widget as IAjaxClientControl;
			((IAjaxClientControl)m_eventWidget.Widget).processAjaxEvent(m_browserStateDoc.DocumentElement);
		}

		string actionBizProc = m_browserStateDoc.DocumentElement.GetAttribute("id");
		ActiveBizProc bp = BPC.getActiveBizProc(actionBizProc);
		if (bp != null)
		{
			string methodName = m_browserStateDoc.DocumentElement.GetAttribute("event");
			string methodParam = m_browserStateDoc.DocumentElement.GetAttribute("value");
			if (Cmn.IsEmpty(methodParam))
				Cmn.callMethod(bp.BizProc, methodName, new Type[] { }, new object[] { });
			else
				Cmn.callMethod(bp.BizProc, methodName, new Type[] { typeof(String) }, new object[] { methodParam });
		}

	}

	protected override void OnPreRender(EventArgs e)
	{
		//Because going through the initial list of active bizprocs could add more to the list, we must actually
		//make a seperate list and go through that one first and force show and then again to catch
		//the extra ones that didnt show yet.
		List<ActiveBizProc> bpcs = new List<ActiveBizProc>(BPC.ActiveBizProcs.Count);
		foreach (ActiveBizProc b in BPC.ActiveBizProcs.Values)
			bpcs.Add(b);
		foreach (ActiveBizProc b in bpcs)
			b.BizProc.showData(ForceLevel.mustShowGetAllDataIfNeeded);

		foreach (ActiveBizProc b in BPC.ActiveBizProcs.Values)
			if (!bpcs.Contains(b))
				b.BizProc.showData(ForceLevel.mustShowGetAllDataIfNeeded);

		foreach (BizProcOfflineState offline in BPC.PageState.BizProcStates.Values)
			foreach (List<ParentBizProcInfo> pinfo in offline.ParentBizProcs.Values)
				if (pinfo[0].ParentId == "_all")
				{
					ActiveBizProc b = BPC.getActiveBizProc(offline.Id);
					b.BizProc.showData(ForceLevel.mustShowGetAllDataIfNeeded);
				}
		base.OnPreRender(e);
	}

	protected override void Render(System.Web.UI.HtmlTextWriter writer)
	{
		//Create the response back to the browser client, using the states of the control
		XmlDocument resp = new XmlDocument();
		resp.LoadXml("<AjaxResponse />");
		XmlElement states = resp.CreateElement("ControlStates");
		resp.DocumentElement.AppendChild(states);
		if (!Cmn.IsEmpty(m_newView))
		{
			resp.DocumentElement.SetAttribute("gotoView", m_newView);
		}
		else
		{

			//Try to used the event widget's main bizproc to get its "currentId" so that it can be written in the
			//root element as an attribute.  This is used for events like movenext/previous so that the
			//browser javascript can setup a history point in the browser using the id of the current bizobj.
			//if the user goes back with the back button it can use a bizobjselected event to get back to that state.
			if (m_eventWidget != null && !Cmn.IsEmpty(m_eventWidget.Widget.ParentBizProcIds))
			{
				string[] parentIds = m_eventWidget.Widget.ParentBizProcIds.Split(',');
				string parentBizProcId = parentIds[0].Split('.')[0];
				ActiveBizProc bp = BPC.getActiveBizProc(parentBizProcId);
				if (bp != null)
				{
					IBizObj bizObj = bp.BizProc.CurrentBizObj;
					if (bizObj != null)
					{
						string bizObjId = bizObj.KeyValue == null ? "" : bizObj.KeyValue.ToString();
						resp.DocumentElement.SetAttribute("curId", bizObjId);
					}
				}
			}

			m_localizer = new Swaf.Gui.AspNet2.ServerControlLocalizer(BPC.PageState.PageId);
			if (m_localizer != null && m_localizer.ShouldTrackPageFields)
			{
				localizeControls(Controls);
				if (m_localizer.UiViewLocalizationInfo != null && m_localizer.UiViewLocalizationInfo.Count > 0)
				{
					IBizObj uiView = m_localizer.UiViewLocalizationInfo[0];
					IResults rc = App.ruleMgr.execute("addApplicationView", uiView);
				}
			}


			foreach (ActiveWidget widget in BPC.ActiveWidgets.Values)
				setupWidgetClientXml(widget, states, true, null);

			string pageHtml = getPageHtml();

			foreach (ActiveWidget widget in BPC.ActiveWidgets.Values)
				setupWidgetClientXml(widget, states, false, pageHtml);

		}
		string xml = resp.DocumentElement.OuterXml;
		try
		{
			string ajaxOutLoc = (string)App.appData.get("AjaxDebugOutput");
			if (!Cmn.IsEmpty(ajaxOutLoc))
				File.WriteAllText(Cmn.pathCombine(ajaxOutLoc, "Out-" + DateTime.Now.ToString("yyMMddHHmmssF") + ".xml"), xml);
		}
		catch (Exception) { }

		Context.Response.Write(xml);
		Context.Response.End();

	}

	private void localizeControls(ControlCollection controls)
	{
		foreach (Control ctl in controls)
			if (ctl is MasterPage || ctl is ContentPlaceHolder || ctl is HtmlForm || ctl is Swaf.Gui.AspNet2.UserControl)
				localizeControls(ctl.Controls);
			else if (!(ctl is LiteralControl) && ctl.ID != null)
				m_localizer.localizeControl(ctl, this, "");
	}

	protected void setupWidgetClientXml(ActiveWidget widget, XmlElement states, bool preRender, string pageHtml)
	{
		if (widget.Widget is IAjaxClientControl && !widget.CreatedFromPage && ((Control)widget.Widget).Page != null &&
			((!preRender && ((IAjaxClientControl)widget.Widget).NeedToGenerateHtmlWithServerControls) ||
			(preRender && !((IAjaxClientControl)widget.Widget).NeedToGenerateHtmlWithServerControls)))
		{
			IAjaxClientControl ctl = widget.Widget as IAjaxClientControl;
			XmlElement stateEl = states.OwnerDocument.CreateElement("State");
			stateEl.SetAttribute("id", ctl.WidgetId);
			ctl.getState(stateEl, pageHtml);
			states.AppendChild(stateEl);
		}
	}

	protected string getPageHtml()
	{
		string pageHtml = null;
		bool needToGen = false;
		foreach (ActiveWidget widget in BPC.ActiveWidgets.Values)
			if (!(widget.Widget is IAjaxClientControl && ((IAjaxClientControl)widget.Widget).NeedToGenerateHtmlWithServerControls))
				m_pageForm.Controls.Remove((Control)widget.Widget);
			else
				needToGen = true;
		if (needToGen)
		{
			StringWriter swr = new StringWriter();
			HtmlTextWriter html = new HtmlTextWriter(swr);

			//base.Render(html);
			Form.RenderControl(html);
			pageHtml = swr.ToString();
			return pageHtml;
		}
		return pageHtml;
	}

	protected string PageStateSessionId
	{
		get
		{
			if (m_pageRequestId.EndsWith("popup_aspx"))
				return "PopupPageState";
			else
				return "ActivePageState";
		}
	}

	public BizProcCoordinator BPC
	{
		get
		{
			if (m_bpc == null)
			{
				ViewOfflineState pageState = PageStateManager.getState(m_pageRequestId, false);
				if (pageState == null)
					throw new BaseException(string.Format("No page state found in session using key :{0}:", m_pageRequestId));
				m_bpc = new BizProcCoordinator(this, pageState);
			}
			return m_bpc;
		}
		set
		{
			m_bpc = value;
		}
	}
	protected Swaf.IApplication App { get { return Swaf.Application.currentApp; } }

	public void BizProcCreated(ActiveBizProc bizProc)
	{
	}

	private bool m_inWidgetCreated = false;
	public void WidgetCreated(ActiveWidget widget)
	{
		if (m_inWidgetCreated)
			return;
		if (widget.Widget is IAjaxClientControl)
		{
			IAjaxClientControl ctl = widget.Widget as IAjaxClientControl;
			ctl.CreateOnLoad = false;
		}
		if (((Control)widget.Widget).Page == null)
		{
			m_inWidgetCreated = true;
			m_pageForm.Controls.Add(widget.Widget as Control);
			m_inWidgetCreated = false;
		}

		if (widget.Widget is IAjaxClientControl)
		{
			IAjaxClientControl ctl = widget.Widget as IAjaxClientControl;
			XmlElement stateEl = m_browserStateDoc.DocumentElement.SelectSingleNode("//ControlStates/State[@id = '" + ctl.WidgetId + "']") as XmlElement;
			if (stateEl != null)
				ctl.setState(stateEl);
		}
	}
	public void gotoView(string name)
	{
		if (name.IndexOf(':') == -1 && 
			((Swaf.BizRule.IRuleManagerEx)Swaf.Application.globalApp.ruleMgr).getRuleInfo("isSecurePage", false) != null)
		{
			Uri first = (Uri)App.sessionData.get("firstUrl");
			string hostUrl = first.Host + ":443";

			bool isSecure = false;
			Swaf.IResults rc = App.ruleMgr.execute("isSecurePage", name);
			if (rc.CallResults is bool)
				isSecure = (bool)rc.CallResults;
			if (isSecure)
				name = "https://" + hostUrl + name;
		}

		m_newView = name; 
	}
	public String ViewName { get { return m_pageRequestId; } }
	public bool IsAjaxEvent { get { return true; } }
}
